#region Using

using System;
using System.Collections.Generic;

#endregion

namespace BlogEngine.Core
{
	/// <summary>
	/// Albums are a way to organize photos. A photo can be in multiple Albums.
	/// </summary>
	[Serializable]
	public class Album : RelateableBase<Album>, IComparable<Album>
	{
		#region Constructor

		/// <summary>
		/// Initializes a new instance of the <see cref="Album"/> class.
		/// </summary>
		public Album()
			: base()
		{
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="title"></param>
		/// <param name="slug"></param>
		/// <param name="description"></param>
		public Album(string title, string slug, string description)
			: base()
		{
			this.Title = title;
			this.Slug = string.IsNullOrEmpty(slug) ? Utils.RemoveIllegalCharacters(title) : Utils.RemoveIllegalCharacters(slug);
			this.Description = description;
			this.Order = Album.GetNextOrder();
		}

		#endregion

		#region Base overrides


		/// <summary>
		/// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
		/// </returns>
		public override string ToString()
		{
			return Title;
		}

		#endregion

		#region IComparable<Album> Members

		/// <summary>
		/// Compares the current object with another object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.</param>
		/// <returns>
		/// A 32-bit signed integer that indicates the relative order of the 
		/// objects being compared. The return value has the following meanings: 
		/// Value Meaning Less than zero This object is less than the other parameter.Zero 
		/// This object is equal to other. Greater than zero This object is greater than other.
		/// </returns>
		public int CompareTo(Album other)
		{
			return CompareOrderAndTitle(this.Order, DateTime.MinValue, this.Title, other.Order, DateTime.MinValue, other.Title);
		}

		#endregion

		protected override string RelativeLinkPrefix()
		{
			return "album/";
		}

		protected override string PermaLinkPrefix()
		{
			return "album";
		}

		#region Methods

		/// <summary>
		/// Returns albums by page
		/// </summary>
		public static List<Album> GetByAlbumsByPage(int page)
		{
			/// todo: cache results, and re-use
			List<Album> list = new List<Album>();

			int perpage = BlogSettings.Instance.GalleryColumns * BlogSettings.Instance.GalleryRows;
			int skip = (page - 1) * perpage;
			int cnt = 0;

			foreach (Album album in Album.Items)
				if ((album.Count > 0) && (album.IsPublished))
				{
					cnt++;
					if (cnt >= skip)
						list.Add(album);

					if (list.Count == perpage)
						break;
				}

			return list;
		}

		/// <summary>
		/// Saves the object to the database.
		/// </summary>
		public new void Save()
		{
			DateModified = DateTime.Now;
			base.Save();
		}

		#endregion

		#region Sort Methods

		/// <summary>
		/// Swaps two albums sort order positions
		/// </summary>
		static public void SwapOrder(Album album1, Album album2)
		{
			if ((album1 == album2) || (album1 == null) || (album2 == null))
				return;

			// if order numbers are the same, reinitalize all the order numbers
			// required to avoid infinite loops based on the assumption that
			// order numbers are unique
			if (album1.Order == album2.Order)
				ReInitalizeOrderNumbers();

			int order = album1.Order;

			album1.Order = album2.Order;
			album2.Order = order;

			album1.Save();
			album2.Save();
			Album.Items.Sort();
		}

		/// <summary>
		/// Moves given album up one position
		/// </summary>
		static public void MoveUp(Album album)
		{
			SwapOrder(album, album.Previous);
		}

		/// <summary>
		/// Moves given album down one position
		/// </summary>
		static public void MoveDown(Album album)
		{
			SwapOrder(album, album.Next);
		}

		/// <summary>
		/// Moves given album to the first position
		/// </summary>
		static public void MoveFirst(Album album)
		{
			// slow, but works
			while (album.Previous != null)
				MoveUp(album);
		}

		/// <summary>
		/// Moves given album to the last position
		/// </summary>
		static public void MoveLast(Album album)
		{
			// slow, but works
			while (album.Next != null)
				MoveDown(album);
		}

		/// <summary>
		/// Gets the next available sort order number
		/// </summary>
		static public int GetNextOrder()
		{
			int maxorder = 1;

			foreach (Album album in Album.Items)
				if (album.Order >= maxorder)
					maxorder = album.Order;

			return maxorder + 1;
		}

		/// <summary>
		/// reinitalized all the sort order numbers
		/// </summary>
		static public void ReInitalizeOrderNumbers()
		{
			List<Album> list = new List<Album>();

			foreach (Album album in Album.Items)
				list.Add(album);

			for (int i = 0; i < list.Count; i++)
			{
				if (list[i].Order != i)
				{
					list[i].Order = i;
					list[i].Save();
				}
			}

			Album.Items.Sort();
		}

		#endregion

		#region Properties

		private string _TagString = string.Empty;
		public string TagString
		{
			get { return _TagString; }
			set { _TagString = value; }
		}

		private string _Keywords = string.Empty;
		/// <summary>
		/// Gets or sets the Keywords or the object.
		/// </summary>
		public string Keywords
		{
			get { return _Keywords; }
			set
			{
				if (_Keywords != value) MarkChanged("Keywords");
				_Keywords = value;
			}
		}

		private StateList<PhotoEffect> _PhotoEffects = new StateList<PhotoEffect>();
		/// <summary>
		/// Gets the photo effects.
		/// </summary>
		public StateList<PhotoEffect> PhotoEffects
		{
			get
			{
				return _PhotoEffects;
			}
		}

		/// <summary>
		/// Returns the first photo in the album
		/// </summary>
		public List<Photo> Photos
		{
			get
			{
				return Photo.GetByAlbum(this);
			}
		}

		/// <summary>
		/// Returns the first photo in the album
		/// </summary>
		public Photo FirstPhoto
		{
			get
			{
				if (Photos.Count == 0)
					return Photo.EmptyPhoto;
				else
					return Photos[0];
			}
		}
		/// <summary>
		/// Returns the number of photos in album
		/// </summary>
		public int Count
		{
			get
			{
				return Photos.Count;
			}
		}

		/// <summary>
		/// Gets if the item has been changed.
		/// </summary>
		public override bool IsChanged
		{
			get
			{
				if (base.IsChanged)
					return true;

				if (PhotoEffects.IsChanged)
					return true;

				return false;
			}
		}

		#endregion

		#region Data Access

		static internal BlogEngine.Core.Provider.Interfaces.IAlbums AlbumProvider = BlogEngine.Core.Provider.BlogService.Provider.GetInterface<BlogEngine.Core.Provider.Interfaces.IAlbums>();

		protected override void DataDelete()
		{
			AlbumProvider.Delete(this);
		}

		protected override void DataInsert()
		{
			AlbumProvider.Insert(this);
		}

		protected override Album DataSelect(Guid id)
		{
			return AlbumProvider.Select(id);
		}

		protected override void DataUpdate()
		{
			AlbumProvider.Update(this);
		}

		private static int Dummy = OverrideOnLoad();

		private static int OverrideOnLoad()
		{
			OnLoad = AlbumProvider.Fill;
			return 0;
		}

		#endregion

	}
}
